# Functions:

# Function to standardize columns of a matrix
# where you designate a standardization group
# (e.g., the control group in an experiment)
# with "sgroup", a logical vector.

matStand <- function(x, sgroup = rep(TRUE, nrow(x)), na.rm=T){
  for(j in 1:ncol(x)){
    x[,j] <- (x[,j] - mean(x[sgroup,j], na.rm=T))/sd(x[sgroup,j], na.rm=T)
  }
  return(x)
}

# Function that takes in data in matrix format and returns
# (i) IC weights and (ii) ICW index.
# Weights can be incorporated using the "wgts" argument.
# The "revcols" argument takes a vector indicating which columns,
# if any, should have values reversed (that is, standardized 
# values are multiplied by -1) prior to construction of the index.

# With missing values
# function to scale weights
weightScale <- function(xmat, weights) {
  missx <- xmat
  missx[is.na(xmat)] <- 0
  missx[!is.na(xmat)] <- 1
  scale <- weights%*%t(missx)
  return(scale)
}

# function to replace NAs
matMiss <- function(xmat) {
  xindex <- xmat
  xindex[is.na(xmat)] <- 0
  return(xindex)
}

icwIndex <- function(	xmat,
                      wgts=rep(1, nrow(xmat)),
                      revcols = NULL,
                      sgroup = rep(TRUE, nrow(xmat))){
  X <- matStand(xmat, sgroup)
  if(length(revcols)>0){
    X[,revcols] <-  -1*X[,revcols]
  }
  i.vec <- as.matrix(rep(1,ncol(xmat)))
  Sx <- cov(X, use="pairwise.complete.obs")
  weights <- solve(t(i.vec)%*%solve(Sx)%*%i.vec)%*%t(i.vec)%*%solve(Sx)
  scale <- weightScale(X,weights)
  xindex <- matMiss(X)
  index <- t((weights%*%t(xindex))/scale)
  return(list(weights = weights, index = index))
}

# function to create subindex from index by rescaling weights from index to sum 1
subindexRescale <- function(xmat, weightsv, startc, endc, sgroup) {
  weights_sub <- weightsv[startc:endc]
  weights_scale <- weights_sub/sum(weights_sub)
  X <- matStand(xmat, sgroup)
  scale <- weightScale(X,weights_scale)
  xindex <- matMiss(X)
  index <- t((weights_scale%*%t(xindex))/scale)
  return(index)
}
